package de.fhkl.gatav.ut.bubbles_minus1;

import java.util.LinkedList;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;

/****
 * bubblesView: Manages display handling of app. Implements SurfaceHolder.Callback to access certain display properties
 */
public class BubblesView extends SurfaceView implements SurfaceHolder.Callback {

	private SurfaceHolder surfaceHolder = null;						//Surface to hijack
	private GameLoop gameLoop;										//Display refresh thread
	private Paint backgroundPaint = new Paint();					//Certain paint properties and objects
	private Paint bubblePaint = new Paint();
	private static final int RADIUS = 10;
	private static final float DEG_TO_RAD = (float)(2*3.141529/360.0);
	
	private float x, y;												//Positional parameters of drawing
	private int alpha = 0;
	
/****
 * Constructor
 * @param context
 * @param attrs
 */
	public BubblesView(Context context, AttributeSet attrs) {
		super(context, attrs);
		getHolder().addCallback((Callback) this);	//Register this class as callback handler for the surface
		backgroundPaint.setColor(Color.BLUE);		//Create a blue color painter for backgroud
		bubblePaint.setStyle(Paint.Style.FILL);
		bubblePaint.setColor(Color.RED);			//Bubble color
	}

/****
 * drawScreen: Paints background and a circle	
 * @param c: Canvas to be drawn on
 */
	private void drawScreen(Canvas c) {
		c.drawRect(0, 0, c.getWidth(), c.getHeight(), backgroundPaint); //Draw background
		c.drawOval(new RectF(x-RADIUS, y-RADIUS, x+RADIUS, y+RADIUS), 	//Draw bubbles
				   bubblePaint);									
	}

/****
 * calculateDisplay: calculates new circle position	
 * @param canvas: Canvas to calculate moves for
 */
	private void calculateDisplay(Canvas canvas) {	
		final float width = canvas.getWidth()/4;
		final float height = canvas.getHeight()/4; 
		
		x = width * (float)Math.cos(alpha*DEG_TO_RAD) + 2*width;	//The circle will move on a circular path
		y = height * (float)Math.sin(alpha*DEG_TO_RAD) + 2*height;
		if (alpha < 360) alpha++; else alpha=0;
	}
 
/****
 * Private display loop thread	
 */
	private class GameLoop extends Thread {
		private long msPerFrame = 1000/25;	//Frame rate
		public boolean running = true;		//Control flag for start / stop mechanism
		private long frameTime = 0;			//Clock to timing control

/****
 * run is the standard routine called, when a thread is started via the start() method	
 */		
		public void run() {
			Canvas canvas = null;
			final SurfaceHolder surfaceHolder = BubblesView.this.surfaceHolder;
			
			frameTime = System.currentTimeMillis();			//Implementation alternative (2) with optimized system calls (see (*) below)
			while (running) {
//				frameTime = System.currentTimeMillis();		//Implementation alternative (1) which needs one more system call (see (*) below)
				try {
					canvas = surfaceHolder.lockCanvas();	//Get the canvas exclusively
					synchronized (surfaceHolder) {			//Must be executed exclusively
						calculateDisplay(canvas);			//Calculate new frame
						drawScreen(canvas);					//Draw new calculated frame
					}
				} finally {
					if (canvas != null)
						surfaceHolder.unlockCanvasAndPost(canvas);
				}
				waitTillNextFrame();
			}
		}
		
		private void waitTillNextFrame() {
			long nextSleep = 0;
			
			//(*) see above) Implementation alternative (2) with optimized system calls
			frameTime += msPerFrame;							
			nextSleep = frameTime - System.currentTimeMillis();					//This calculates the EXACT time to wait for frames	
			
			//((*) see above) Implementation alternative (1) which needs one more system call
//			nextSleep = msPerFrame -(System.currentTimeMillis() - frameTime);	
			
			Log.d("nextSleepDuration", String.valueOf(nextSleep));
			
			if (nextSleep > 0) {												//Wait to every msPerFrame. Keeping the
				try {															//processing time into account
					sleep(nextSleep);
//					sleep(msPerFrame);											//Try this line instead, if you don't believe
				} catch (InterruptedException e) {
				}
			}
		}
	}
		      			
/****
 * Interfcae implementation	
 */
	
/****
 * Called when display is up	
 */
	public void surfaceCreated(SurfaceHolder holder) {
		surfaceHolder = holder;
		synchronized (this) {				//Must be executed exclusively
			if (gameLoop == null) {
				gameLoop = new GameLoop();	//Start animation here
				gameLoop.start();
			}
		}
	}
	
/****
 * Not used	
 */
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		//Nothing to do
	}
	
/****
 * Called before display will be brought down	
 */
	public void surfaceDestroyed(SurfaceHolder holder) {
		synchronized (this) {				//Must be executed exclusively
			boolean retry = true;
			if (gameLoop != null) {			//Stop the loop
				gameLoop.running = false;
				while (retry) {
					try {
						gameLoop.join();	//Catch the thread
						retry = false;
					} catch (InterruptedException e) {
					}
				}
			}
			gameLoop = null;
		}
	}
}